import { injectable } from '@/services/service'
import { Worker, createWorker } from 'tesseract.js'
import { invoke, convertFileSrc } from '@tauri-apps/api/tauri'
import { appCacheDir, documentDir, join } from '@tauri-apps/api/path'
import { createDir, readTextFile, exists, readDir, writeTextFile, BaseDirectory, removeFile } from '@tauri-apps/api/fs'
import { ref } from 'vue'

const identifier = 'tech.jiyun.ascum'
const rois = {
  '3360_1440': [
    [1060, 667, 80, 36],

    [2220, 667, 80, 36],
    [2220, 740, 80, 36],

    [1830, 258, 75, 26],
    [1830, 362, 75, 26],
    [1830, 464, 75, 26],
    [1830, 568, 75, 26],
    [1830, 672, 75, 26],
    [1830, 775, 75, 26],
    [1830, 878, 75, 26],
    [1830, 980, 75, 26],

    [1960, 258, 75, 26],
    [1960, 362, 75, 26],
    [1960, 464, 75, 26],
    [1960, 568, 75, 26],
    [1960, 672, 75, 26],
    [1960, 775, 75, 26],
    [1960, 878, 75, 26],
    [1960, 980, 75, 26]
  ]
  // '1920_1080': [
  //   [493, 500, 62, 28],

  //   [1365, 500, 62, 28],
  //   [1365, 555, 60, 28],

  //   [1070, 193, 60, 24],
  //   [1070, 272, 60, 24],
  //   [1070, 346, 60, 24],
  //   [1070, 424, 60, 24],
  //   [1070, 504, 60, 24],
  //   [1070, 582, 60, 24],
  //   [1070, 658, 60, 24],
  //   [1070, 736, 60, 24],

  //   [1168, 193, 60, 24],
  //   [1168, 272, 60, 24],
  //   [1168, 346, 60, 24],
  //   [1168, 424, 60, 24],
  //   [1168, 504, 60, 24],
  //   [1168, 582, 60, 24],
  //   [1168, 658, 60, 24],
  //   [1168, 736, 60, 24]
  // ]
} as { [key: string]: number[][] }

@injectable
/** 开门服务 */
export default class DoorService {
  rois = ref(rois['3360_1440'])

  private worker!: Worker
  private imgFilePath = ''
  private canvas = document.createElement('canvas')

  private inputValue = 0
  private outputValue = {
    v1: 0,
    v2: 0
  }

  private calcValueL = [] as string[]
  private calcValueR = [] as string[]
  private resultValue = new Array(8).fill(false) as boolean[]

  constructor () {
    const isFs = location.protocol === 'file:'

    createWorker({
      workerPath: (isFs ? location.href.slice(0, location.href.slice(0, -3).lastIndexOf('/')) : location.origin) + '/worker.min.js',
      corePath: (isFs ? location.href.slice(0, location.href.slice(0, -3).lastIndexOf('/')) : location.origin) + '/tesseract-core.wasm.js',
      logger: m => console.log(m),
      langPath: (isFs ? location.href.slice(0, location.href.slice(0, -3).lastIndexOf('/')) : location.origin) + '/',
      gzip: false
    }).then(async w => {
      this.worker = w
      await this.worker.loadLanguage('eng')
      await this.worker.initialize('eng')
      await this.worker.setParameters({
        tessedit_char_whitelist: '0123456789+-*/.'
      })

      this.imgFilePath = await join(await appCacheDir(), '__cap_for_ascum.png')
    });

    (async () => {
      if (!await exists(identifier, { dir: BaseDirectory.Document })) {
        await createDir(identifier, { dir: BaseDirectory.Document })
        await writeTextFile(identifier + '\\3360_1440.screen.json', JSON.stringify([
          [1060, 667, 80, 36],

          [2220, 667, 80, 36],
          [2220, 740, 80, 36],

          [1830, 258, 75, 26],
          [1830, 362, 75, 26],
          [1830, 464, 75, 26],
          [1830, 568, 75, 26],
          [1830, 672, 75, 26],
          [1830, 775, 75, 26],
          [1830, 878, 75, 26],
          [1830, 980, 75, 26],

          [1960, 258, 75, 26],
          [1960, 362, 75, 26],
          [1960, 464, 75, 26],
          [1960, 568, 75, 26],
          [1960, 672, 75, 26],
          [1960, 775, 75, 26],
          [1960, 878, 75, 26],
          [1960, 980, 75, 26]
        ]), { dir: BaseDirectory.Document })
        await writeTextFile(identifier + '\\1920_1080.screen.json', JSON.stringify([
          [493, 498, 62, 30],
          [1365, 498, 62, 30],
          [1365, 553, 60, 30],

          [1070, 192, 60, 24],
          [1070, 270, 60, 24],
          [1070, 346, 60, 24],
          [1070, 424, 60, 24],
          [1070, 501, 60, 24],
          [1070, 580, 60, 24],
          [1070, 656, 60, 24],
          [1070, 734, 60, 24],

          [1168, 192, 60, 24],
          [1168, 270, 60, 24],
          [1168, 346, 60, 24],
          [1168, 424, 60, 24],
          [1168, 501, 60, 24],
          [1168, 580, 60, 24],
          [1168, 656, 60, 24],
          [1168, 734, 60, 24]
        ]), { dir: BaseDirectory.Document })
        await createDir(identifier + '/imgs', { dir: BaseDirectory.Document, recursive: true })
      }
      const scFiles = await readDir(identifier, { dir: BaseDirectory.Document })
      for (const f of scFiles.filter(v => !v.children?.length && v.path.endsWith('.screen.json'))) {
        try {
          const sccfg = JSON.parse(await readTextFile(identifier + '/' + f.name, { dir: BaseDirectory.Document })) as number[][]
          if (Array.isArray(sccfg) && sccfg.length === 19 && sccfg.findIndex(v => v.length !== 4) < 0) {
            rois[f.name!.slice(0, -12)] = sccfg
          }
        } catch { }
      }
      this.rois.value = rois[`${window.screen.width}_${window.screen.height}`]
      if (!this.rois.value) {
        this.rois.value = rois['3360_1440']
      }
      console.log(this.rois.value)
    })()

    //
    this.canvas.style.cssText = 'position: fixed;top:0;left:0;z-index:100000;opacity:0;'
    document.body.appendChild(this.canvas)
  }

  private async capture(now: number) {
    // 截图
    const file = await join(await documentDir(), identifier, 'imgs', 'capture_' + now + '.png')
    await invoke('capture', { file })
    // 加载图片
    const img = new Image()
    img.src = convertFileSrc(file) + '?v=' + Math.random()
    img.crossOrigin = 'anonymous'

    await new Promise(res => {
      let timer = setTimeout(() => res(null), 18000)
      img.onload = async () => {
        clearTimeout(timer)
        res(img)
      }
    })
    return img
  }

  async detect () {
    const now = Date.now()
    const img = await this.capture(now)
    const rect = await invoke('get_position')
    console.log(1212, rect)
    let results = [] as string[]
    const mat = cv.imread(img)
    cv.cvtColor(mat, mat, cv.COLOR_BGR2GRAY)
    const _rois = rois[`${img.width}_${img.height}`]
    if (!_rois) {
      throw `缺少 ${img.width}x${img.height} 的配置文件`
    }
    // 识别
    this.rois.value = _rois
    for (let i = 0; i < _rois.length; i++) {
      const _mat = mat.roi(new cv.Rect(..._rois[i]))
      if (_rois[i][3] !== 45) {
        cv.resize(_mat, _mat, new cv.Size(Math.round(_rois[i][2] * 45 / _rois[i][3]), 45))
      }
      // 调整亮度
      for (let i = 0; i < _mat.rows; i++) {
        for (let j = 0; j < _mat.cols; j++) {
          _mat.ucharPtr(i, j)[0] = Math.max(0, Math.min(255, Math.round(_mat.ucharPtr(i, j)[0] * 1.7 - 105)))
        }
      }
      this.canvas.width = Math.round(_rois[i][2] * 45 / _rois[i][3])
      this.canvas.height = 45
      cv.imshow(this.canvas, _mat)
      const { data: { text } } = await this.worker.recognize(this.canvas.toDataURL())
      results[i] = text.trim()
      _mat.delete()
    }
    mat.delete()
    removeFile(identifier + '/imgs/capture_' + now + '.png', { dir: BaseDirectory.Document })
    results = results.map((v, i) => {
      if (i < 3) {
        return v
      }
      if (!v) {
      } else if (v.charCodeAt(0) > 47) {
        v = '*' + v
      } else if (v.length < 3 && !v.startsWith('/')) {
        v = '*' + v.slice(1)
      }
      return v
    })
    return results // {outputs: undefined, results}
    // const outputs = await this.openDoor(results)
    // if (outputs?.find(v => v)) {
    //   removeFile(identifier + '/imgs/capture_' + now + '.png', { dir: BaseDirectory.Document })
    //   return {outputs, results: undefined}
    // } else {
    //   writeTextFile(identifier + '/imgs/' + now + '.txt', results.join('\n'), { dir: BaseDirectory.Document })
    //   return {outputs: undefined, results}
    // }
    // const file = await join(await documentDir(), identifier, 'imgs', 'capture_' + now + '.png')
    // await invoke('capture', { file })
    // // await invoke('capture', { file: this.imgFilePath })
    // const img = new Image()
    // // img.src = convertFileSrc(this.imgFilePath) + '?v=' + Math.random()
    // img.src = convertFileSrc(file) + '?v=' + Math.random()
    // img.crossOrigin = 'anonymous'
    // return await new Promise<null | boolean[]>(res => {
    //   const timer = setTimeout(() => res(null), 18000)
    //   img.onload = async () => {
    //     const results = [] as string[]
    //     const mat = cv.imread(img)
    //     cv.cvtColor(mat, mat, cv.COLOR_BGR2GRAY)
    //     const _rois = rois[`${img.width}_${img.height}`]
    //     if (!_rois) {
    //       res(null)
    //       clearTimeout(timer)
    //       throw `缺少 ${img.width}x${img.height} 的配置文件`
    //     }
    //     this.rois.value = _rois
    //     for (let i = 0; i < _rois.length; i++) {
    //       const _mat = mat.roi(new cv.Rect(..._rois[i]))
    //       if (_rois[i][3] !== 45) {
    //         cv.resize(_mat, _mat, new cv.Size(Math.round(_rois[i][2] * 45 / _rois[i][3]), 45))
    //       }
    //       for (let i = 0; i < _mat.rows; i++) {
    //         for (let j = 0; j < _mat.cols; j++) {
    //           _mat.ucharPtr(i, j)[0] = Math.max(0, Math.min(255, Math.round(_mat.ucharPtr(i, j)[0] * 1.7 - 105)))
    //         }
    //       }
    //       this.canvas.width = Math.round(_rois[i][2] * 45 / _rois[i][3])
    //       this.canvas.height = 45
    //       cv.imshow(this.canvas, _mat)
    //       const { data: { text } } = await this.worker.recognize(this.canvas.toDataURL())
    //       results[i] = text.trim()
    //       _mat.delete()
    //       if (i === 18) {
    //         clearTimeout(timer)
    //         const outputs = await this.openDoor(results)
    //         if (outputs?.find(v => v)) {
    //           removeFile(identifier + '/imgs/capture_' + now + '.png', { dir: BaseDirectory.Document })
    //         } else {
    //           writeTextFile(identifier + '/imgs/' + now + '.txt', results.join('\n'), { dir: BaseDirectory.Document })
    //         }
    //         res(outputs)
    //       }
    //     }
    //     mat.delete()
    //   }
    // })
  }

  openDoor (results: string[]) {
    this.inputValue = +results[0]
    this.outputValue = {
      v1: +results[1],
      v2: +results[2]
    }
    results.forEach((v, i) => {
      if (i < 3) {
        return
      }
      if (!v) {
        //
      } else if (v.charCodeAt(0) > 47) {
        v = '*' + v
      } else if (v.length < 3 && !v.startsWith('/')) {
        v = '*' + v.slice(1)
      }
      if (i > 10) {
        this.calcValueR[i - 11] = v
      } else {
        this.calcValueL[i - 3] = v
      }
    })
    this.resultValue = new Array(8).fill(false)
    for (let i = 0; i < 8; i++) {
      for (let j = 0; j < 8; j++) {
        if (this.check(j, i + 1, { v1: this.inputValue, v2: this.inputValue })) {
          return this.resultValue
        }
      }
    }
    return null
  }

  // @ts-ignore
  // eslint-disable-next-line no-new-func, no-template-curly-in-string
  private execFunc = new Function('v', 'op', 'return eval(`${v}${op || ""}`)')

  private check (index: number, onN: number, input = { v1: 0, v2: 0 }): boolean {
    if (index + onN > 8) {
      return false
    }
    const _v1 = this.execFunc(input.v1, this.calcValueL[index])
    const _v2 = this.execFunc(input.v2, this.calcValueR[index])
    if (onN > 1) {
      if (this.check(index + 1, onN - 1, { v1: _v1, v2: _v2 })) {
        console.log(index, onN)
        this.resultValue[index] = true
        return true
      } else {
        return this.check(index + 1, onN, input)
      }
    } else {
      if (_v1 === this.outputValue.v1 && _v2 === this.outputValue.v2) {
        console.log(index, 1)
        this.resultValue[index] = true
        return true
      }
      return this.check(index + 1, onN, input)
    }
  }
}
